using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;

namespace Tycho.Peyote.Mock {
    public class ListItemReorderer {
        struct ItemsAboveBelow {
            public ListItem Above, Below;
        }

        private ItemsControl ItemsControl;
        private ListItem MovingItem;
        private ItemsAboveBelow InternalNearItems;
        private double MovingItemHeight;
        private int IndexToInsert;

        public ListItemReorderer (ItemsControl itemsControl) {
            ItemsControl = itemsControl;
        }

        void SetNearItems(int above, int below) {
            ItemsAboveBelow nearItems = new ItemsAboveBelow();

            if (above >= 0) {
                nearItems.Above = (ListItem) ItemsControl.Items [above];
            }
            if (below < ItemsControl.Items.Count) {
                nearItems.Below = (ListItem) ItemsControl.Items [below];
            }

            MakeGap (0);
            InternalNearItems = nearItems;
            MakeGap (MovingItemHeight);

            IndexToInsert = below;
        }

        void ClearNearItems() {
            ClearGap ();
            InternalNearItems = new ItemsAboveBelow {Above = null, Below = null};
        }

        private void MakeGap (double height) {
            double marginHeight;

            if (InternalNearItems.Above != null ^ InternalNearItems.Below != null) {
                marginHeight = height;
            } else {
                marginHeight = height/2;
            }

            Debug.WriteLine ("marginHeight = " + marginHeight);

            Storyboard sb = new Storyboard ();
            if (InternalNearItems.Above != null) {
                Debug.WriteLine ("setting margin for item above");
                var margin = InternalNearItems.Above.Margin;
                var newMargin = new Thickness (0, 0, 0, marginHeight);
                var animation = new ThicknessAnimation (margin, newMargin, new Duration (new TimeSpan (0, 0, 0, 0, 100)));
                sb.Children.Add (animation);
                InternalNearItems.Above.BeginAnimation (FrameworkElement.MarginProperty, animation);
            }
            if (InternalNearItems.Below != null) {
                Debug.WriteLine ("setting margin for item below");
                var margin = InternalNearItems.Below.Margin;
                var newMargin = new Thickness (0, marginHeight, 0, 0);
                var animation = new ThicknessAnimation (margin, newMargin, new Duration (new TimeSpan (0, 0, 0, 0, 100)));
                InternalNearItems.Below.BeginAnimation (FrameworkElement.MarginProperty, animation);
            }
        }

        private void ClearGap() {
            if (InternalNearItems.Above != null) {
                InternalNearItems.Above.BeginAnimation (FrameworkElement.MarginProperty, null);
                InternalNearItems.Above.Margin = new Thickness (0, 0, 0, 0);
            }
            if (InternalNearItems.Below != null) {
                InternalNearItems.Below.BeginAnimation (FrameworkElement.MarginProperty, null);
                InternalNearItems.Below.Margin = new Thickness (0, 0, 0, 0);
            }
        }

        public void StartReorder (ListItem movingItem) {
            MovingItem = movingItem;

            MovingItemHeight = MovingItem.ActualHeight;
            int index = ItemsControl.Items.IndexOf (MovingItem);

            SetNearItems (index - 1, index + 1);

            Debug.WriteLine ("removing moving item, ItemsControl.Items.Count = " + ItemsControl.Items.Count);
            ItemsControl.Items.Remove (MovingItem);
            Debug.WriteLine ("removed moving item, ItemsControl.Items.Count = " + ItemsControl.Items.Count);
        }

        public void DragOver (ListItem overElement, DragEventArgs eventArgs) {
            if (eventArgs.GetPosition (overElement).Y > overElement.ActualHeight / 2) {
                int index = ItemsControl.Items.IndexOf (overElement);
                Debug.WriteLine ("below element index = " + index);
                SetNearItems (index, index + 1);
            } else {
                int index = ItemsControl.Items.IndexOf (overElement);
                Debug.WriteLine ("above element index = " + index);
                SetNearItems (index - 1, index);
            }
        }

        public void Drop () {
            Debug.WriteLine ("index to insert = " + IndexToInsert);
            if (IndexToInsert == ItemsControl.Items.Count) {
                ItemsControl.Items.Add (MovingItem);
            } else {
                ItemsControl.Items.Insert (IndexToInsert, MovingItem);
            }
            ClearNearItems ();
        }
    }
}